import numpy as np
import math
# 初始化输入数据i1、i2的值
i1 = 0.05;i2 = 0.10
# 初始化标签值target_01、target_02的值
target_o1 = 0.01; target_o2 = 0.99
# 初始化学习率
learning_rate = 0.5
# 初始化输入层->隐藏层的权重
w1 = 0.15;w2 = 0.20;w3 = 0.25;w4 = 0.30
# 初始化隐藏层->输出层的权重
w5 = 0.40;w6 = 0.45;w7 = 0.50;w8 = 0.55
# 初始化偏置值b1,b2
b1 = 0.35;b2 = 0.60 

# 实现sigmoid函数
def sigmoid(x):
    return 1. / (1 + np.exp(-x))

# Step1 前向传播
# 输入层--->隐藏层
# 计算隐藏层中神经元h1的输入加权和
net_h1 = w1 * i1 + w2 * i2 + b1 * 1
net_h2 = w3 * i1 + w4 * i2 + b1 * 1
# 神经元h1输出到o1:(此处用到激活函数为sigmoid)
out_h1 = sigmoid(net_h1)
# 神经元h2输出到o2:(此处用到激活函数为sigmoid)
out_h2 = sigmoid(net_h2)
# 隐含层---->输出层：
# 计算输出层神经元o1和o2的值：
net_o1 = w5 * out_h1 + w6 * out_h2 + b2 * 1
net_o2 = w7 * out_h1 + w8 * out_h2 + b2 * 1

# 计算神经元o1和o2的值：
out_o1 = sigmoid(net_o1)
out_o2 = sigmoid(net_o2)

# Step2 反向传播
# 1.计算总误差 （Square error）
def E_total():
    return (np.square(target_o1 - out_o1) + np.square(target_o2 - out_o1))*0.5

# 2. 隐藏层--->输出层的权值更新：
# 以权重参数w5为例，如果我们想知道w5对整体误差产生了多少影响，可以用整体误差对w5求偏导（链式法则）

def Etotal_w5678(target, out_o, out_h):
    return -(target - out_o) * out_o * (1 - out_o) * out_h
# 输出层误差
def E_out(target, out_o):
    return -(target - out_o) *  out_o * (1 - out_o)
# 输出层误差
def Etotal_w1234(target_1, out_o1, w_ho1, target_2, out_o2, w_ho2, out_h, i):
    return ((E_out(target_1, out_o1)) * w_ho1 + (E_out(target_2, out_o2)) * w_ho2) *out_h*(1-out_h)*i  

for i in range(100000):
     #对应分别是期望输出1，输出1，输出1和h1的权重，期望输出2，输出2，输出2和h1的权重，h1的输出，输入i1
    w1 = w1 - learning_rate*Etotal_w1234(target_o1,out_o1,w5,target_o2,out_o2,w7,out_h1,i1)
    w2 = w2 - learning_rate*Etotal_w1234(target_o1,out_o1,w5,target_o2,out_o2,w7,out_h1,i1)
    w3 = w3 - learning_rate*Etotal_w1234(target_o1,out_o1,w5,target_o2,out_o2,w7,out_h1,i1)
    w4 = w4 - learning_rate*Etotal_w1234(target_o1,out_o1,w5,target_o2,out_o2,w7,out_h1,i1)

    w5=w5-learning_rate*Etotal_w5678(target_o1,out_o1,out_h1)
    w6=w6-learning_rate*Etotal_w5678(target_o1,out_o1,out_h2)
    w7=w7-learning_rate*Etotal_w5678(target_o2,out_o2,out_h1)
    w8=w8-learning_rate*Etotal_w5678(target_o2,out_o2,out_h2)
    
    net_h1 = i1*w1 + i2*w2 + b1
    net_h2 = i1*w3 + i2*w4 + b1

    out_h1 = sigmoid(net_h1)
    out_h2 = sigmoid(net_h2)

    net_o1 = out_h1*w5 + out_h2*w6 + b2
    net_o2 = out_h1*w7 + out_h2*w8 + b2

    out_o1 = sigmoid(net_o1)
    out_o2 = sigmoid(net_o2)
    if(i%10000==0):
        print("第{}次反向传播后，误差为{}".format(i,E_total()))

print("最终输出：",out_o1,out_o2)
print("目标输出：",target_o1,target_o2)
print("偏差值为：",target_o1-out_o1,target_o2-out_o2)
# print(w1)